/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University. All rights reserved.
 * 
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license; 2) All redistributions in binary form
 * must reproduce the above copyright notice, this list of conditions and the
 * disclaimer listed in this license in the documentation and/or other materials
 * provided with the distribution; 3) Any documentation included with all
 * redistributions must include the following acknowledgement:
 * 
 * "This product includes software developed by the Community Grids Lab. For
 * further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/."
 * 
 * Alternatively, this acknowledgement may appear in the software itself, and
 * wherever such third-party acknowledgments normally appear.
 * 
 * 4) The name Indiana University or Community Grids Lab or NaradaBrokering,
 * shall not be used to endorse or promote products derived from this software
 * without prior written permission from Indiana University. For written
 * permission, please contact the Advanced Research and Technology Institute
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202. 5) Products
 * derived from this software may not be called NaradaBrokering, nor may Indiana
 * University or Community Grids Lab or NaradaBrokering appear in their name,
 * without prior written permission of ARTI.
 * 
 * 
 * Indiana University provides no reassurances that the source code provided
 * does not infringe the patent or any other intellectual property rights of any
 * other entity. Indiana University disclaims any liability to any recipient for
 * claims brought by any other entity based on infringement of intellectual
 * property rights or otherwise.
 * 
 * LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
 * WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 * NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 * INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 * INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 * "VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 * LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 * ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 * GENERATED USING SOFTWARE.
 */
package cgl.narada.service.qos.impl;

import java.security.PublicKey;
import java.util.Properties;

import javax.crypto.SecretKey;

import cgl.narada.matching.Profile;
import cgl.narada.service.ServiceException;
import cgl.narada.service.qos.ConsumerConstraints;
import cgl.narada.service.qos.QosIdentifiers;
import cgl.narada.service.security.kmc.SignedSecurityToken;

/**
 * Allows a consumer to specify QosConstraints on the sending or receiving of
 * events conforming to a given profile
 * 
 * @author Shrideep Pallickara $Date$ $Revision$
 */

public class ConsumerConstraintsImpl implements ConsumerConstraints {

    private int entityId = 0;
    private int consumerId = 0;
    private int templateId = 0;

    private Profile profile;
    private int constraintId;

    private boolean receiveInOrder = false;
    private boolean receiveReliably = false;
    private boolean receiveSecurely = false;
    private boolean receiveAfterPayloadDecompression = false;
    private boolean receiveAfterCoalescingFragments = false;

    private boolean receiveInTimeOrder = false;
    private boolean receiveAfterTimeSpacing = false;

    private String moduleName = "ConsumerConstraintsImpl: ";

    // HG:
    private PublicKey rootCAPublicKey = null;
    private SignedSecurityToken signedSecurityToken = null;
    private SecretKey secretKey = null;
    private Properties securityProps = null;
    private boolean deliverWithoutDecryption = false;
    // ---

    public ConsumerConstraintsImpl(int entityId, int consumerId,
            Profile profile, int constraintId) {
        this.entityId = entityId;
        this.consumerId = consumerId;
        this.profile = profile;
        this.constraintId = constraintId;
        this.signedSecurityToken = null;
        this.secretKey = null;
        this.securityProps = null;
    }

    public int getEntityId() {
        return entityId;
    }

    public int getConsumerId() {
        return consumerId;
    }

    /**
     * Returns the templateId associated with the consumer constraint. There can
     * be only one consumer constraint associated with a given consumer. If the
     * templateId has NOT BEEN SET by one of the setter method, this method WILL
     * RETURN 0. Otherwise it will return the value of the templateId
     */
    public int getTemplateId() {
        return templateId;
    }

    public Profile getProfile() {
        return profile;
    }

    public int getConstraintIdentifier() {
        return constraintId;
    }

    /**
     * Enable ordered delivery of events corresponding to this template. This
     * method will throw an exception if the templateId specified during any of
     * the previous invocations of methods (with the templateId argument) is
     * different from the one specified in this method
     */
    public void setReceiveInOrder(int ordTemplateId) throws ServiceException {
        if (templateId != 0) {
            if (templateId != ordTemplateId) {
                throw new ServiceException(moduleName
                        + "Specified templateId [" + ordTemplateId
                        + "] different from previously "
                        + "specified templateId of " + templateId);
            }
            receiveInOrder = true;
        }

        templateId = ordTemplateId;
        receiveInOrder = true;
    }

    /**
     * Ensures that events are ordered in time before they are released. The
     * events are buffered for a duration of time prior to the release.
     */
    public void setReceiveInTimeOrder() {
        receiveInTimeOrder = true;
    }

    /**
     * Ensures that events are spaced in time before they are released. This
     * feature is traditionally used during the replay of audio-video multimedia
     * streams
     */
    public void setReceiveAfterTimeSpacing() {
        receiveAfterTimeSpacing = true;
    }

    /**
     * Enable reliable delivery of events corresponding to this template This
     * method will throw an exception if the templateId specified during any of
     * the previous invocations of methods (with the templateId argument) is
     * different from the one specified in this method
     */
    public void setReceiveReliably(int recTemplateId) throws ServiceException {
        if (templateId != 0) {
            if (templateId != recTemplateId) {
                throw new ServiceException(moduleName
                        + "Specified templateId [" + recTemplateId
                        + "] different from previously "
                        + "specified templateId of " + templateId);
            }
            receiveReliably = true;
        }

        templateId = recTemplateId;
        receiveReliably = true;
    }

    /**
     * Enable secure delivery of events corresponding to this template. This
     * method will throw an exception if the templateId specified during any of
     * the previous invocations of methods (with the templateId argument) is
     * different from the one specified in this method
     */
    public void setReceiveSecurely(int secTemplateId) throws ServiceException {
        
        // TODO: IS template Id required ? 
        
        if (templateId != 0) {
            if (templateId != secTemplateId) {
                throw new ServiceException(moduleName
                        + "Specified templateId [" + secTemplateId
                        + "] different from previously "
                        + "specified templateId of " + templateId);
            }
            receiveSecurely = true;
        }

        templateId = secTemplateId;
        receiveSecurely = true;
    }

    public void setReceiveAfterPayloadDecompression() {
        receiveAfterPayloadDecompression = true;
    }

    public boolean isReceiveInOrder() {
        return receiveInOrder;
    }

    public boolean isReceiveInTimeOrder() {
        return receiveInTimeOrder;
    }

    public boolean isReceiveAfterTimeSpacing() {
        return receiveAfterTimeSpacing;
    }

    public boolean isReceiveReliably() {
        return receiveReliably;
    }

    public boolean isReceiveSecurely() {
        return receiveSecurely;
    }

    public boolean isReceiveAfterPayloadDecompression() {
        return receiveAfterPayloadDecompression;
    }

    public boolean isReceiveAfterCoalescingFragments() {
        return receiveAfterCoalescingFragments;
    }

    public void setReceiveAfterCoalescingFragments() {
        receiveAfterCoalescingFragments = true;
    }

    public boolean hasSatisfiedSpecifiedConstraints(QosIdentifiers identifiers) {

        boolean satisfied = true;

        if (receiveReliably) {
            if (!identifiers.isArchived()) {
                satisfied = false;
            }
        }

        if (receiveInOrder) {
            if (!identifiers.isOrdered()) {
                satisfied = false;
            }
        }

        if (receiveInTimeOrder) {
            if (!identifiers.isTimeOrdered()) {
                satisfied = false;
            }
        }

        if (receiveAfterTimeSpacing) {
            if (!identifiers.isTimeSpaced()) {
                satisfied = false;
            }
        }

        return satisfied;

    }

    /** end hasSatisfiedSpecifiedConstraints */

    // HG:
    /**
     * Sets the security token for recieving events over a secure topic<br>
     * NOTE: This is a non-optional requirement for subscribing to secure topics
     * 
     * @param sst -
     *            The signed security token as obtained from a KMC
     * @param key -
     *            The secret key associated with the topic. This will be used to
     *            decrypt the payload
     */
    public void setSecurityToken(SignedSecurityToken sst, SecretKey key,
            Properties props, boolean doNotDecryptPayloadBeforeDelivery, PublicKey rootCAPubKey) {        
        this.signedSecurityToken = sst;
        this.secretKey = key;
        this.securityProps = props;
        this.deliverWithoutDecryption = doNotDecryptPayloadBeforeDelivery;
        this.rootCAPublicKey = rootCAPubKey;
    }

    public SignedSecurityToken getSignedSecurityToken() {
        return this.signedSecurityToken;
    }

    public SecretKey getSecretKey() {
        return this.secretKey;
    }

    public Properties getDecryptionProperties() {
        return this.securityProps;
    }

    public boolean isNoDecryptionRequested() {
        return deliverWithoutDecryption;
    }

    public PublicKey getRootCAPublicKey() {
        return rootCAPublicKey;
    }

    // ---
}
